home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 2008 by Steve Krulewitz <skrulx@gmail.com>
- * Licensed under GPLv2 or later, see file LICENSE in the xpi for details.
- */
- const Cc = Components.classes;
- const Ci = Components.interfaces;
- const Cr = Components.results;
- const Cu = Components.utils;
-
- const MINUTE_IN_MS = 60 * 1000;
-
- const DEBUG = false;
-
- const NS_PROFILE_STARTUP_OBSERVER_ID = "profile-after-change";
- const NS_PROFILE_SHUTDOWN_OBSERVER_ID = "profile-before-change";
-
- const UPDATE_URL = "http://skrul.com/projects/greasefire/update.php";
-
- const JARFILES = ["include.dat", "exclude.dat", "scripts.db", "info.ini"];
-
- function TRYIGNORE(aFunc) {
- try {
- aFunc();
- }
- catch (e) {
- Cu.reportError(e);
- }
- }
-
- function d(s) {
- if (DEBUG) {
- dump("gfUpdaterService: " + s + "\n");
- }
- }
-
- function gfUpdaterService() {
- d("ctor");
-
- this._gfs = null;
- this._prefs = null;
- this._isUpdating = false;
- this._listeners = [];
-
- this._nextUpdate = null;
- this._timer = null;
- this._wbp = null;
- this._timer;
-
- var obs = Cc["@mozilla.org/observer-service;1"]
- .getService(Ci.nsIObserverService);
- obs.addObserver(this, NS_PROFILE_STARTUP_OBSERVER_ID, false);
- obs.addObserver(this, NS_PROFILE_SHUTDOWN_OBSERVER_ID, false);
- }
-
- gfUpdaterService.prototype = {
- classDescription: "Greasefire Updater Service",
- classID: Components.ID("{7c5b9317-0b18-4390-9a0a-a594d544a99f}"),
- contractID: "@skrul.com/greasefire/updater;1"
- }
-
- gfUpdaterService.prototype._startup =
- function gfUpdaterService__startup()
- {
- d("startup");
-
- this._gfs = Cc["@skrul.com/greasefire/service;1"]
- .getService(Ci.gfIGreasefireService);
-
- this._prefs = Cc["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefService)
- .getBranch("greasefire.");
-
- // If we are overdue for an update at startup, push it a minute in the future
- // so we don't slow down startup
- if (this.updateIntervalMinutes > 0 && Date.now() > this.nextUpdateDate) {
- this._updateNextUpdateDate(1);
- }
-
- this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- this._timer.initWithCallback(this,
- MINUTE_IN_MS,
- Ci.nsITimer.TYPE_REPEATING_SLACK);
- }
-
- gfUpdaterService.prototype._shutdown =
- function gfUpdaterService__shutdown()
- {
- d("shutdown");
-
- if (this._timer) {
- this._timer.cancel();
- this._timer = null;
- }
- }
-
- gfUpdaterService.prototype._updateNextUpdateDate =
- function gfUpdaterService__updateNextUpdateDate(aMinutes)
- {
- var ms = aMinutes * MINUTE_IN_MS;
- this._prefs.setCharPref("next_update_date", Date.now() + ms);
- }
-
- gfUpdaterService.prototype._processDownload =
- function gfUpdaterService__processDownload()
- {
- var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
- .createInstance(Ci.nsIZipReader);
-
- var status = Cr.NS_OK;
- var message = "OK";
-
- try {
- zipReader.open(this._dest);
- JARFILES.forEach(function(e) {
- zipReader.test(e);
- });
-
- // Create a temp dir for unpacking
- var em = Cc["@mozilla.org/extensions/manager;1"]
- .getService(Ci.nsIExtensionManager);
- var installLocation = em.getInstallLocation("greasefire@skrul.com");
- var exDir = installLocation.location;
- exDir.append("greasefire@skrul.com");
-
- var unpackDir = exDir.clone();
- unpackDir.append("indexes.new");
- unpackDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0755);
-
- JARFILES.forEach(function(e) {
- var f = unpackDir.clone();
- f.append(e);
- zipReader.extract(e, f);
- });
-
- var oldIndexDir = exDir.clone();
- oldIndexDir.append("indexes");
-
- var backupDir = exDir.clone();
- backupDir.append("indexes.backup");
- backupDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0755);
-
- // Stop the greasefire service and move the dirs around
- this._gfs.shutdown();
- try {
- if (oldIndexDir.exists()) {
- oldIndexDir.moveTo(backupDir, "");
- }
- unpackDir.moveTo(null, "indexes");
- this._gfs.startup();
- }
- catch (e) {
- // Something went wrong, move things back
- Cu.reportError("Error moving indexes " + e.message);
- status = Cr.NS_ERROR_FAILURE;
- message = "Error moving indexes: " + e.message;
-
- unpackDir.remove(true);
- oldIndexDir.moveTo(exDir, "");
- this._gfs.startup();
- }
-
- // Everything is ok, delete the backup dir
- backupDir.remove(true);
- }
- catch (e) {
- Cu.reportError(e);
- if (status = Cr.NS_OK) {
- status = Cr.NS_ERROR_FAILURE;
- message = e.message;
- }
- }
-
- TRYIGNORE(function() {
- zipReader.close();
- });
-
- this._updateFinished(status, message);
- }
-
- gfUpdaterService.prototype._updateFinished =
- function gfUpdaterService__updateFinished(aStatus, aMessage) {
-
- this._isUpdating = false;
-
- if (this._dest) {
- var dest = this._dest;
- TRYIGNORE(function() {
- dest.remove(false);
- });
- this._dest = null;
- }
-
- if (this._wbp) {
- this._wbp.progressListener = null;
- }
- this._wbp = null;
-
- this._notify(function(l) {
- l.onUpdateFinished(aStatus, aMessage);
- });
- }
-
- gfUpdaterService.prototype._notify =
- function gfUpdaterService__notify(aFunc)
- {
- this._listeners.forEach(function(l) {
- try {
- aFunc(l);
- }
- catch (e) {
- Cu.reportError(e);
- }
- });
- }
-
- // gfIUpdaterService
- gfUpdaterService.prototype.startUpdate =
- function gfUpdaterService_startUpdate(aForce)
- {
- if (this._isUpdating) {
- return;
- }
-
- this._isUpdating = true;
- this._notify(function(l) {
- l.onUpdateStarted();
- });
-
- try {
- this._wbp = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
- .createInstance(Ci.nsIWebBrowserPersist);
- this._wbp.progressListener = this;
-
- // Create a destination file for the download
- this._dest = Cc["@mozilla.org/file/directory_service;1"]
- .getService(Ci.nsIProperties)
- .get("TmpD", Ci.nsIFile);
- this._dest.append("greasefire_index_download.jar");
- this._dest.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
-
- // Start the download
- var ios = Cc["@mozilla.org/network/io-service;1"]
- .getService(Ci.nsIIOService);
- var uri = ios.newURI(UPDATE_URL, null, null);
-
- var headers = null;
- if (this._gfs.indexDate > 0 && !aForce) {
- headers = "If-Modified-Since: " +
- (new Date(this._gfs.indexDate)).toGMTString() + "\r\n";
- }
-
- this._wbp.saveURI(uri, null, null, null, headers, this._dest);
- }
- catch (e) {
- // Something went wrong setting up the download.
- Cu.reportError(e);
- this._updateFinished(Cr.NS_ERROR_FAILURE, e.message);
- }
-
- }
-
- gfUpdaterService.prototype.cancelUpdate =
- function gfUpdaterService_cancelUpdate()
- {
- if (this._isUpdating && this._wbp) {
- this._wbp.cancelSave();
- }
- }
-
- gfUpdaterService.prototype.__defineGetter__("isUpdating",
- function gfUpdaterService_get_isUpdating()
- {
- return this._isUpdating;
- });
-
- gfUpdaterService.prototype.__defineGetter__("nextUpdateDate",
- function gfUpdaterService_get_nextUpdateDate()
- {
- try {
- return parseInt(this._prefs.getCharPref("next_update_date"));
- }
- catch(e) {
- }
- return 0;
- });
-
- gfUpdaterService.prototype.__defineGetter__("updateIntervalMinutes",
- function gfUpdaterService_get_updateIntervalMinutes()
- {
- try {
- return this._prefs.getIntPref("update_interval_minutes");
- }
- catch(e) {
- }
- return 0;
- });
-
- gfUpdaterService.prototype.__defineSetter__("updateIntervalMinutes",
- function gfUpdaterService_set_updateIntervalMinutes(aMinutes)
- {
- this._prefs.setIntPref("update_interval_minutes", aMinutes);
- this._updateNextUpdateDate(aMinutes);
- });
-
- gfUpdaterService.prototype.addListener =
- function gfUpdaterService_addListener(aListener)
- {
- if (this._listeners.indexOf(aListener) >= 0) {
- return;
- }
- this._listeners.push(aListener);
- }
-
- gfUpdaterService.prototype.removeListener =
- function gfUpdaterService_removeListener(aListener)
- {
- this._listeners.filter(function(e) {
- return aListener != e;
- });
- }
-
- // nsIWebProgressListener
- gfUpdaterService.prototype.onStateChange =
- function gfUpdaterService_onStateChange(aWebProgress,
- aRequest,
- aStateFlags,
- aStatus)
- {
- d("onStateChange");
- if (this._isUpdating && aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
-
- if (this._wbp.result == Cr.NS_BINDING_ABORTED) {
- this._updateFinished(Cr.NS_BINDING_ABORTED, "Cancelled");
- return;
- }
-
- var responseStatus = null;
- try {
- responseStatus = aRequest.QueryInterface(Ci.nsIHttpChannel).responseStatus;
- }
- catch (e) {
- }
-
- if (responseStatus == 200) {
- this._processDownload();
- return;
- }
-
- if (responseStatus == 304) {
- this._updateFinished(Cr.NS_ERROR_FILE_ALREADY_EXISTS, "Not Modified");
- return;
- }
-
- this._updateFinished(Cr.NS_ERROR_FAILURE,
- "status = 0x" + aStatus.toString(16) + " " +
- "http = " + responseStatus);
- }
- }
-
- gfUpdaterService.prototype.onProgressChange =
- function gfUpdaterService_onProgressChange(aWebProgress,
- aRequest,
- aCurSelfProgress,
- aMaxSelfProgress,
- aCurTotalProgress,
- aMaxTotalProgress)
- {
- if (this._isUpdating) {
- this._notify(function(l) {
- l.onDownloadProgress(aCurTotalProgress, aMaxTotalProgress);
- });
- }
- }
-
- gfUpdaterService.prototype.onLocationChange =
- function gfUpdaterService_onLocationChange(aWebProgress, aRequest, aLocation)
- {
- }
-
- gfUpdaterService.prototype.onStatusChange =
- function gfUpdaterService_onStatusChange(aWebProgress,
- aRequest,
- aStatus,
- aMessage)
- {
- }
-
- gfUpdaterService.prototype.onSecurityChange =
- function gfUpdaterService_onSecurityChange(aWebProgress, aRequest, aState)
- {
- }
-
- // nsITimer
- gfUpdaterService.prototype.notify =
- function gfUpdaterService_notify(aTimer)
- {
- if (this.updateIntervalMinutes > 0 && Date.now() > this.nextUpdateDate) {
- this._updateNextUpdateDate(this.updateIntervalMinutes);
- this.startUpdate(false);
- }
- }
-
- // nsIObserver
- gfUpdaterService.prototype.observe =
- function gfUpdaterService_observe(aSubject, aTopic, aData)
- {
- if (aTopic == NS_PROFILE_STARTUP_OBSERVER_ID) {
- this._startup();
- }
- else if (aTopic == NS_PROFILE_SHUTDOWN_OBSERVER_ID) {
- this._shutdown();
- var obs = Cc["@mozilla.org/observer-service;1"]
- .getService(Ci.nsIObserverService);
- obs.removeObserver(this, NS_PROFILE_STARTUP_OBSERVER_ID);
- obs.removeObserver(this, NS_PROFILE_SHUTDOWN_OBSERVER_ID);
- }
- }
-
- /*
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Alex Fritze <alex@croczilla.com> (original author)
- * Nickolay Ponomarev <asqueella@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
- /**
- * Utilities for JavaScript components loaded by the JS component
- * loader.
- *
- * Import into a JS component using
- * 'Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");'
- *
- * Exposing a JS 'class' as a component using these utility methods consists
- * of several steps:
- * 0. Import XPCOMUtils, as described above.
- * 1. Declare the 'class' (or multiple classes) implementing the component(s):
- * function MyComponent() {
- * // constructor
- * }
- * MyComponent.prototype = {
- * // properties required for XPCOM registration:
- * classDescription: "unique text description",
- * classID: Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
- * contractID: "@example.com/xxx;1",
- *
- * // [optional] custom factory (an object implementing nsIFactory). If not
- * // provided, the default factory is used, which returns
- * // |(new MyComponent()).QueryInterface(iid)| in its createInstance().
- * _xpcom_factory: { ... },
- *
- * // [optional] an array of categories to register this component in.
- * _xpcom_categories: [{
- * // Each object in the array specifies the parameters to pass to
- * // nsICategoryManager.addCategoryEntry(). 'true' is passed for
- * // both aPersist and aReplace params.
- * category: "some-category",
- * // optional, defaults to the object's classDescription
- * entry: "entry name",
- * // optional, defaults to the object's contractID (unless
- * // 'service' is specified)
- * value: "...",
- * // optional, defaults to false. When set to true, and only if 'value'
- * // is not specified, the concatenation of the string "service," and the
- * // object's contractID is passed as aValue parameter of addCategoryEntry.
- * service: true
- * }],
- *
- * // QueryInterface implementation, e.g. using the generateQI helper
- * QueryInterface: XPCOMUtils.generateQI(
- * [Components.interfaces.nsIObserver,
- * Components.interfaces.nsIMyInterface]),
- *
- * // ...component implementation...
- * };
- *
- * 2. Create an array of component constructors (like the one
- * created in step 1):
- * var components = [MyComponent];
- *
- * 3. Define the NSGetModule entry point:
- * function NSGetModule(compMgr, fileSpec) {
- * // components is the array created in step 2.
- * return XPCOMUtils.generateModule(components);
- * }
- */
-
- var XPCOMUtils = {
- /**
- * Generate a QueryInterface implementation. The returned function must be
- * assigned to the 'QueryInterface' property of a JS object. When invoked on
- * that object, it checks if the given iid is listed in the |interfaces|
- * param, and if it is, returns |this| (the object it was called on).
- */
- generateQI: function(interfaces) {
- return makeQI([i.name for each(i in interfaces)]);
- },
-
- /**
- * Generate the NSGetModule function (along with the module definition).
- * See the parameters to generateModule.
- */
- generateNSGetModule: function(componentsArray, postRegister, preUnregister) {
- return function NSGetModule(compMgr, fileSpec) {
- return XPCOMUtils.generateModule(componentsArray,
- postRegister,
- preUnregister);
- }
- },
-
- /**
- * Generate a module implementation.
- *
- * @param componentsArray Array of component constructors. See the comment
- * at the top of this file for details.
- * @param postRegister optional post-registration function with
- * signature 'postRegister(nsIComponentManager,
- * nsIFile, componentsArray)'
- * @param preUnregister optional pre-unregistration function with
- * signature 'preUnregister(nsIComponentManager,
- * nsIFile, componentsArray)'
- */
- generateModule: function(componentsArray, postRegister, preUnregister) {
- let classes = [];
- for each (let component in componentsArray) {
- classes.push({
- cid: component.prototype.classID,
- className: component.prototype.classDescription,
- contractID: component.prototype.contractID,
- factory: this._getFactory(component),
- categories: component.prototype._xpcom_categories
- });
- }
-
- return { // nsIModule impl.
- getClassObject: function(compMgr, cid, iid) {
- // We only support nsIFactory queries, not nsIClassInfo
- if (!iid.equals(Ci.nsIFactory))
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-
- for each (let classDesc in classes) {
- if (classDesc.cid.equals(cid))
- return classDesc.factory;
- }
-
- throw Cr.NS_ERROR_FACTORY_NOT_REGISTERED;
- },
-
- registerSelf: function(compMgr, fileSpec, location, type) {
- var componentCount = 0;
- debug("*** registering " + fileSpec.leafName + ": [ ");
- compMgr.QueryInterface(Ci.nsIComponentRegistrar);
-
- for each (let classDesc in classes) {
- debug((componentCount++ ? ", " : "") + classDesc.className);
- compMgr.registerFactoryLocation(classDesc.cid,
- classDesc.className,
- classDesc.contractID,
- fileSpec,
- location,
- type);
- if (classDesc.categories) {
- let catMan = XPCOMUtils.categoryManager;
- for each (let cat in classDesc.categories) {
- let defaultValue = (cat.service ? "service," : "") +
- classDesc.contractID;
- catMan.addCategoryEntry(cat.category,
- cat.entry || classDesc.className,
- cat.value || defaultValue,
- true, true);
- }
- }
- }
-
- if (postRegister)
- postRegister(compMgr, fileSpec, componentsArray);
- debug(" ]\n");
- },
-
- unregisterSelf: function(compMgr, fileSpec, location) {
- var componentCount = 0;
- debug("*** unregistering " + fileSpec.leafName + ": [ ");
- compMgr.QueryInterface(Ci.nsIComponentRegistrar);
- if (preUnregister)
- preUnregister(compMgr, fileSpec, componentsArray);
-
- for each (let classDesc in classes) {
- debug((componentCount++ ? ", " : "") + classDesc.className);
- if (classDesc.categories) {
- let catMan = XPCOMUtils.categoryManager;
- for each (let cat in classDesc.categories) {
- catMan.deleteCategoryEntry(cat.category,
- cat.entry || classDesc.className,
- true);
- }
- }
- compMgr.unregisterFactoryLocation(classDesc.cid, fileSpec);
- }
- debug(" ]\n");
- },
-
- canUnload: function(compMgr) {
- return true;
- }
- };
- },
-
- /**
- * Convenience access to category manager
- */
- get categoryManager() {
- return Components.classes["@mozilla.org/categorymanager;1"]
- .getService(Ci.nsICategoryManager);
- },
-
- /**
- * Returns an nsIFactory for |component|.
- */
- _getFactory: function(component) {
- var factory = component.prototype._xpcom_factory;
- if (!factory) {
- factory = {
- createInstance: function(outer, iid) {
- if (outer)
- throw Cr.NS_ERROR_NO_AGGREGATION;
- return (new component()).QueryInterface(iid);
- }
- }
- }
- return factory;
- }
- };
-
- /**
- * Helper for XPCOMUtils.generateQI to avoid leaks - see bug 381651#c1
- */
- function makeQI(interfaceNames) {
- return function XPCOMUtils_QueryInterface(iid) {
- if (iid.equals(Ci.nsISupports))
- return this;
- for each(let interfaceName in interfaceNames) {
- if (Ci[interfaceName].equals(iid))
- return this;
- }
-
- throw Cr.NS_ERROR_NO_INTERFACE;
- };
- }
-
- //@line 420 "/home/steve/dev/mozilla/1.8/mozilla/extensions/greasefire/src/gfUpdaterService.js"
-
- gfUpdaterService.prototype.QueryInterface =
- XPCOMUtils.generateQI([Ci.gfIUpdaterService,
- Ci.nsIObserver,
- Ci.nsIWebProgressListener,
- Ci.nsITimerCallback]);
-
- var NSGetModule = XPCOMUtils.generateNSGetModule(
- [
- gfUpdaterService
- ],
- function(aCompMgr, aFileSpec, aLocation) {
- XPCOMUtils.categoryManager.addCategoryEntry(
- "app-startup",
- gfUpdaterService.prototype.classDescription,
- "service," + gfUpdaterService.prototype.contractID,
- true,
- true);
- }
- );
-
- function do(o) {
-
- var s = "";
- if (typeof(o) == "string") {
- s = o;
- }
- else {
- if (o.length) {
- }
- else {
- var a = [];
- for (var k in o) {
- a.push(k + " => " + o[k]);
- }
- s = a.join(", ");
- }
- }
-
- dump("[updater] " + s + "\n");
-
- }
-